﻿#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include "netselect.h"

#define INVALID_SOCKET (-1)
CNetSelect::CNetSelect()  
	: m_socket( socket(AF_INET, SOCK_STREAM, 0) )  
{
}

CNetSelect::~CNetSelect()  
{
}

xgc_void CNetSelect::SendErrorCodeEx( xgc_int32 nErrorCode )  
{
	m_nErrorCode = nErrorCode;  
}

xgc_int32  CNetSelect::Connect( xgc_lpcstr address, xgc_uint16 port )
{  
	struct sockaddr_in ServerAddr;  

	ServerAddr.sin_family = AF_INET;
    inet_aton(address, &(ServerAddr.sin_addr));
	ServerAddr.sin_port = htons( port );

	// int overtime = 1000;  
	// setsockopt( m_socket, SOL_SOCKET, SO_RCVTIMEO, (char*)&overtime, sizeof( overtime ) );  
	// setsockopt( m_socket, SOL_SOCKET, SO_SNDTIMEO, (char*)&overtime, sizeof( overtime ) );  
	xgc_int32 hResult = connect( m_socket, ( const struct sockaddr* )&ServerAddr, sizeof( ServerAddr ) );
	if( hResult == -1 )  
	{
		xgc_int32 nErrorCode = errno;  
		SendErrorCodeEx( nErrorCode );  
		close( m_socket );  
		m_socket = INVALID_SOCKET;  
		return false;  
	}  

	return true;  
}  

xgc_bool CNetSelect::Disconnect()  
{  
	xgc_int32 hResult = close( m_socket );  
	m_socket = INVALID_SOCKET;  
	if( hResult != 0 )  
	{  
		SendErrorCodeEx( errno );  
		return false;  
	}
	return true;  
}  

xgc_int32 CNetSelect::Send( xgc_lpcstr pszBuffer, xgc_size size )  
{
	xgc_int32 send_bytes = 0;
	do
	{
		fd_set fdwrite;  
		timeval tv;  
		tv.tv_sec = 0;
		tv.tv_usec = 10;  

		FD_ZERO(&fdwrite);
		FD_SET(m_socket, &fdwrite);

		xgc_int32 ret = select(m_socket+1, 0, &fdwrite, 0, &tv);
		if( ret < 0 )
		{
			return ret;
		}

		send_bytes += send( m_socket, pszBuffer + send_bytes, size, MSG_NOSIGNAL );
		if( send_bytes < 0 )
		{  
			return send_bytes;
		}  
		size -= send_bytes;
	}while( size > 0 );

	return send_bytes;
}  

xgc_int32 CNetSelect::Recv( xgc_lpstr pszBuffer, xgc_size size )  
{
	xgc_int32 recv_bytes = 0;

	fd_set fdread;  
	timeval tv;  
	tv.tv_sec = 0;
	tv.tv_usec = 10;  

	FD_ZERO(&fdread);
	FD_SET(m_socket, &fdread);

	recv_bytes = select(m_socket+1, &fdread, 0, 0, &tv);
	if( recv_bytes < 0 )
	{  
		return recv_bytes;
	}
	else if( FD_ISSET( m_socket, &fdread ) )  
	{
		recv_bytes = recv( m_socket, pszBuffer, size, MSG_NOSIGNAL );
		return recv_bytes;
	}  
	return recv_bytes;  
}  

